﻿using System;
using System.Collections.Generic;
using Grishko.DataTier;
using OutdoorLib.Context;
using OutdoorLib.BaseEntity.Contract;
using OutdoorLib.BaseEntity.Constraction;

namespace OutdoorLib.BaseEntity.BusinesRules
{
    /// <summary>
    ///  Бизнес логика объектов Контракт,Конструкция,Клиент    
    /// </summary>
    public class BusinesRulesEngine
    {        
        /// <summary>
        /// Внешний обработчик результатов Check
        /// </summary>
        public Func <List<string>, bool> OnError{get;set;}


        /// <summary>
        /// Влделец бизнесс правил 
        /// </summary>
        public Entity Owner=null;

        public virtual void Init()
        {
        }
        
        public virtual bool Check()
        {
            List<string> ErrList = new List<string>();
            if (null != OnError)
                        OnError(ErrList);
            return true;
                    
        }

        public virtual bool OwnerChanging(string FieldName, object NewField)
        {
            if (null == OnError)// Это десерелизация?
                            return true;
            return true;
        }

        public virtual void OwnerAfterChange(string FieldName)
        {
            if (null == OnError)// Это десерелизация?
                return ;
        }
        
    }


    //Конструкция
    public class Constraction_BusinesRulesEngine : BusinesRulesEngine
    {

        public override bool Check()
        {

            ConstractionEntity _Constraction = (ConstractionEntity)Owner;
            List<string> ErrList = new List<string>();
            if (null == _Constraction.ConstractionType)
                ErrList.Add("Не указан тип конструкции");

            //if (null == _Constraction.AdressProgramm || string.IsNullOrEmpty(_Constraction.Streets))
            //    ErrList.Add("Не указан адрес конструкции");

            //if (string.IsNullOrEmpty(_Constraction.GID))
            //    ErrList.Add("Не указан номер конструкции");

            //CheckConstractionNumber(ref ErrList, _Constraction.ID, _Constraction.GID);

            if (OnError != null && ErrList.Count > 0)
                OnError(ErrList);

            return ErrList.Count == 0;

        }

        protected virtual  void CheckConstractionNumber(ref List<string> res, string ID, string Number)
        {
            string sql = "select count(*) from  (select 	ID,	xml.value('/Constraction[1]/@GID','varchar(max)' ) as NN from v_constraction) as source  where not source.ID='{0}'	and source.NN='{1}'";
            string[] r = { ID, Number };
            sql = string.Format(sql, r);
            SqlTools tls = new SqlTools(AppContext.GetSC());
            System.Data.DataSet ds = tls.ExecuteSql(sql);

            if (ds.Tables[0].Rows[0][0].ToString() != "0")
                res.Add("Номер  конструкции не уникален");
        }

        public override bool OwnerChanging(string FieldName, object NewField)
        {
            if (null == OnError)
                return true;

            ConstractionEntity c = (ConstractionEntity)Owner;
            if (FieldName == "GID")
            {
                List<string> l = new List<string>();
                CheckConstractionNumber(ref l, c.ID, NewField.ToString());
                if (l.Count > 0)
                {
                    OnError(l);
                    return false;
                }



            }
            return true;
        }
    }

    //Контракт
    public class Contract_BusinesRulesEngine : BusinesRulesEngine
    {
        public static ContractEntity CreateObject(string ID)
        {
            ContractEntity c = new ContractEntity() { ID = ID };
           // c.ContractStatus = new ContractStatus_Trash();
            return c;

        }

        public override bool Check()
        {
            //ContractEntity _Contract = (ContractEntity)Owner;
            //List<string> ErrList = new List<string>();

            //if (string.IsNullOrEmpty(_Contract.Number))
            //    ErrList.Add("Не указан номер контракта");

            //if (!string.IsNullOrEmpty(_Contract.Number))
            //    CheckContractNumber(ref ErrList, _Contract.ID, _Contract.Number);

            //if (Ecopsy.Tools.DateTimeTools.IsNullOrEmpty(_Contract.SignDate))
            //    ErrList.Add("Не указана дата контракта");


            //if (_Contract.ContractStatus.ID == AgencyLib_GlobalConstants.Contract_Contract)
            //{
            //    if ((_Contract.ContractStatus as ContractStatus_Contract).PaymentsPlan.Summa != _Contract.ContractSurfaceItemList.Summa)
            //        ErrList.Add("Сумма плана платежей не совпадает с суммой согласно списка сторон");
            //}

            //if (OnError != null && ErrList.Count > 0)
            //    OnError(ErrList);

            //return ErrList.Count == 0;
            return false;
        }

        protected virtual  void CheckContractNumber(ref List<string> res, string ID, string Number)
        {
            string sql = "select count(*) from  (select 	ID,	xml.value('/Contract[1]/@Number','varchar(max)' ) as NN from v_contracts) as source where not source.ID='{0}'	and source.NN='{1}'";
            string[] r = { ID, Number };
            sql = string.Format(sql, r);
            SqlTools tls = new SqlTools(AppContext.GetSC());
            System.Data.DataSet ds = tls.ExecuteSql(sql);

            if (ds.Tables[0].Rows[0][0].ToString() != "0")
                res.Add("Номер  контракта не уникален");
        }

        protected virtual void CreateStatus_Contract(ref List<string> res)
        {
            //ContractEntity _Contract = (ContractEntity)Owner;
            //foreach (ContractSurfaceItem item in _Contract.ContractSurfaceItemList)
            //{
            //    if (item.SurfaceNumber > 0)
            //    {
            //        res.Add("Невозможно сформировать план платежей. Существуют стороны носителей находящиеся в очереди.");
            //        return;
            //    }
            //}

            //ContractStatus_Contract s = new ContractStatus_Contract();
            //PaymentsPlanItem i = new PaymentsPlanItem() { Date = _Contract.StartDate, Summa = _Contract.ContractSurfaceItemList.Summa };
            //s.PaymentsPlan.Add(i);
            //_Contract.ContractStatus = s;

        }

        protected virtual void CreateStatus_Reserv()
        {
            //ContractEntity _Contract = (ContractEntity)Owner;
            //// еси текущий статус резерв и появился клиент
            //if (_Contract.ContractStatus is ContractStatus_Advice && _Contract.Client != null)
            //    _Contract.ContractStatus = new ContractStatus_Reserv();

            ////если были в статусе резерв и убрали клиента - переходим в состояние самореклама
            //if (_Contract.ContractStatus is ContractStatus_Reserv && _Contract.Client == null)
            //    _Contract.ContractStatus = new ContractStatus_Advice();

        }

        /// <summary>
        /// Реализация функции по обсчету веса сторон вызывается при изменениии статуса контракта и при изменении поля qPrioritetLevel
        /// </summary>
        /// <returns></returns>
        //protected virtual  bool CalculateContractSurfaceItemList_Weight()
        //{
        //    Contract _Contract = null;
        //    if (Owner is Contract)
        //        _Contract = (Contract)Owner;
        //    if (Owner is ContractSurfaceItem)
        //    {
        //        wsContract ws = (wsContract)AgencyLib_GlobalConstants.CurrentAgency.WS_FactoryList[WS_FactoryList.wsKey_Contract];
        //        _Contract =ws.GetContract((Owner as ContractSurfaceItem).ContractID);
        //    }
 


        //    foreach (ContractSurfaceItem i in _Contract.ContractSurfaceItemList)
        //    {
        //        i.Weight = CalculateStatusWeight(i, _Contract);
        //    }
        //    return true;
        //}

        /// <summary>
        /// Алгоритм устанавливающий вес строчки в очереди 
        /// Высший приоритет =0- контракт
        /// Резерв = defWeight_Reserv - Item.qPrioritetLevel;
        /// Соц.реклама=defWeight_Advice - Item.qPrioritetLevel;
        /// </summary>
        /// <param name="Item"></param>
        /// 
        public const int defWeight_Reserv = 100;
        public const int defWeight_Advice = 150;
        public const int defWeight_Trash = 125;
        public const string CalculateContractSurfaceItemList = "CalculateContractSurfaceItemList";


        public static int CalculateStatusWeight(ContractSurfaceItem Item, ContractEntity Contract)
        {
            return 10;
            ////если контракт - высший приоритет в очереди
            //if (Contract.ContractStatus.ID == AgencyLib_GlobalConstants.Contract_Contract)
            //    return 0;

            ////если резерв  - по умолчанию минус qPrioritetLevel
            //if (Contract.ContractStatus.ID == AgencyLib_GlobalConstants.Contract_Reserv)
            //    return defWeight_Reserv - Item.qPrioritetLevel;

            ////если корзина  - по умолчанию минус qPrioritetLevel
            //if (Contract.ContractStatus.ID == AgencyLib_GlobalConstants.Contract_Reserv)
            //    return defWeight_Trash - Item.qPrioritetLevel;

            ////если реклама  - по умолчанию плюс qPrioritetLevel+1
            //if (Contract.ContractStatus.ID == AgencyLib_GlobalConstants.Contract_Advice)
            //    return defWeight_Advice - Item.qPrioritetLevel;

            //return defWeight_Reserv;
        }


        public override bool OwnerChanging(string FieldName, object NewField)
        {
            if (null == OnError)
                return true;

            ContractEntity _Contract = (ContractEntity)Owner;

            switch (FieldName.ToUpper())
            {
                case "NUMBER":
                    {
                        List<string> l = new List<string>();
                        CheckContractNumber(ref l, (Owner as ContractEntity).ID, NewField.ToString());
                        if (l.Count > 0)
                        {
                            OnError(l);
                            return false;
                        }
                        break;
                    }
                case "CLIENT":
                    // если статус контракта == реклама  и пришел клиент не Null - контракт в статус резервирование 
                    if ((Owner as ContractEntity).ContractStatus is ContractStatus_Advice)
                    {
                        if (null != NewField)
                            (Owner as ContractEntity).ContractStatus = new ContractStatus_Reserv();
                        return true;
                    }


                    // если статус контракта == контракт и пришел клиент Null - сбрасываем контракт в статус реклама 
                    if ((Owner as ContractEntity).ContractStatus is ContractStatus_Contract)
                    {
                        if ((_Contract.ContractStatus as ContractStatus_Contract).PaymentsPlan.Count > 0 || (_Contract.ContractStatus as ContractStatus_Contract).Payments.Count > 0)
                        {
                            List<string> r = new List<string>();
                            r.Add("Существуют записи в плане платежей.");
                            OnError(r);
                            return false;
                        }
                        if (null == NewField)
                            (Owner as ContractEntity).ContractStatus = new ContractStatus_Advice();

                        return true;
                    }

                    break;
                case "CONTRACTSTATUS":
                    {
                        List<string> r = new List<string>();
                        //если мы находились в статусе резерв и пришло   ContractStatus_Contract
                        // Формируем план выплат 
                        if (_Contract.ContractStatus is ContractStatus_Reserv && NewField is ContractStatus_Contract)
                        {
                            foreach (ContractSurfaceItem item in _Contract.ContractSurfaceItemList)
                            {
                                if (_Contract.Client != null)

                                    if (item.SurfaceNumber > 0)
                                    {
                                        r.Add("Невозможно сформировать план платежей. Существуют стороны носителей находящиеся в очереди.");
                                        OnError(r);
                                        return false;
                                    }
                            }


                            ContractStatus_Contract s = (ContractStatus_Contract)NewField;
                            PaymentsPlanItem i = new PaymentsPlanItem() { Date = _Contract.StartDate, Summa = _Contract.ContractSurfaceItemList.Summa };
                            s.PaymentsPlan.Add(i);
                            return true;
                        }

                        //если мы находились в статусе Advice и пришло  ContractStatus_Reserv - выставляем резерв по умолчанию на какое то количестов дней - прописать в настройках 
                        if (_Contract.ContractStatus is ContractStatus_Advice && NewField is ContractStatus_Reserv)
                        {
                            (NewField as ContractStatus_Reserv).dtFinishReserv = DateTime.Now.AddDays(5);
                            return true;
                        }
                        return true;


                    }
            }

            return true;
        }


        public override void OwnerAfterChange(string FieldName)
        {
            if (null == OnError)
                return;

            switch (FieldName)
            {
                //case "qPrioritetLevel":
                //case CalculateContractSurfaceItemList:
                //    CalculateContractSurfaceItemList_Weight();
                //    break;
                default:
                    break;
            }
            base.OwnerAfterChange(FieldName);
        }



    }
}
